package com.yeskery.nut.bean.padding;

import com.yeskery.nut.annotation.bean.Autowired;
import com.yeskery.nut.annotation.bean.Lazy;
import com.yeskery.nut.annotation.bean.LazyInject;
import com.yeskery.nut.annotation.bean.Qualifier;
import com.yeskery.nut.bean.*;
import com.yeskery.nut.util.BeanUtils;
import com.yeskery.nut.util.StringUtils;

import java.lang.reflect.Field;
import java.util.List;

/**
 * Autowired注解属性填充对象
 * @author sprout
 * @version 1.0
 * 2022-07-09 14:54
 */
public class AutowiredAttributePadding extends AbstractAttributePadding {

    /** 应用上下文 */
    private final ApplicationContext applicationContext;

    /** 延迟注入集合 */
    private final List<LazyInjectBeanDefinition> lazyInjectBeanDefinitionList;

    /**
     * 构建Autowired注解属性填充对象
     * @param applicationContext Autowired注解属性填充对象
     * @param lazyInjectBeanDefinitionList 延迟注入集合
     */
    public AutowiredAttributePadding(ApplicationContext applicationContext, List<LazyInjectBeanDefinition> lazyInjectBeanDefinitionList) {
        this.applicationContext = applicationContext;
        this.lazyInjectBeanDefinitionList = lazyInjectBeanDefinitionList;
    }

    @Override
    public void padding(Object object, Field[] fields) {
        for (Field field : fields) {
            if (field.isAnnotationPresent(LazyInject.class)) {
                LazyInjectBeanDefinition lazyInjectBeanDefinition = new LazyInjectBeanDefinition();
                lazyInjectBeanDefinition.setBean(object);
                lazyInjectBeanDefinition.setField(field);
                lazyInjectBeanDefinition.setLazyInjectSupplier(() -> getPaddingValue(object, field));
                lazyInjectBeanDefinitionList.add(lazyInjectBeanDefinition);
            } else {
                try {
                    Object value = getPaddingValue(object, field);
                    if (value != null) {
                        setObjectFileValue(object, field, value);
                    }
                } catch (Exception e) {
                    throw new BeanException("Bean's Attribute [" + field.getType().getName() + "] Name [" + field.getName() + "] Padding Fail.", e);
                }
            }
        }
    }

    /**
     * 获取填充属性值
     * @param field 属性
     * @return 填充值
     */
    private Object getPaddingValue(Object object, Field field) {
        Autowired autowired = field.getAnnotation(Autowired.class);
        Qualifier qualifier = field.getAnnotation(Qualifier.class);
        String name = qualifier == null || StringUtils.isEmpty(qualifier.value()) ? null : qualifier.value();
        Lazy lazy = field.getAnnotation(Lazy.class);
        try {
            Object value;
            if (lazy != null && lazy.value()) {
                value = ((BaseApplicationContext) applicationContext).getProxyObjectContext().createProxyObject(
                        field.getType(), new LazyInjectWrapInvocationHandler(applicationContext, field.getType(), name));
            } else {
                value = BeanUtils.getDependBeanObject(applicationContext, object.getClass(), name, field.getGenericType());
            }
            if (!field.getType().isAssignableFrom(value.getClass())) {
                throw new BeanException("JDK Proxy Bean Object Only Support Interface Inject, " +
                        "If Need Support Class Inject, Need To Introduce Additional Cglib Dependencies.");
            }
            return value;
        } catch (NoSuchBeanException e) {
            if (autowired.required()) {
                throw new BeanException("Bean's Attribute [" + field.getType().getName() + "] Name [" + field.getName() + "] Are Required.", e);
            }
            return null;
        }
    }
}
